WSL 高 CPU 异常排查
1、问题现象
某日打开 VSCode + WSL 开发环境后,即使没有运行任何程序, CPU 使用率长期维持在 80% 以上,风扇全速转动。
观察到:
-
Windows 任务管理器中:
vmmemWSL.exe 占用 70%+ CPU,2.5GB 内存 -
未启动 Docker、VMware ,仅打开 WSL。
-
进入 WSL 内部后使用
top,发现:top - 09:04:47 up 1 min, 1 user, load average: 9.98, 3.12, 1.09
%Cpu(s): 3.1 us, 75.0 sy, 0.0 ni, 20.7 id
...
PID USER %CPU COMMAND
683 root 1197 rg
622 root 22 node
575 root 15 node🔥
rg(ripgrep)单个进程占用 1197% CPU(约 12 核满载)。
2、初步判断:罪魁祸首 vmmemWSL 并非“真凶”
vmmemWSL 只是 WSL 虚拟机的“容器”, 它本身不执行代码,只是承载 Linux 子系统。因此,当 vmmemWSL 占用高时,真正的原因一定是 WSL 内部进程异常。
进一步确认:
wsl --list --verbose
输出:
NAME STATE VERSION
* Ubuntu Running 2
docker-desktop Stopped 2
说明仅有 Ubuntu 在运行。→ 问题出在 Ubuntu 内部进程。
3、深入排查:找到真正的高占用源
执行:
top
发现:
PID 683 root 1197% rg
rg 即 ripgrep,是一种超快的文件搜索工具。通常情况下,VSCode 会在后台使用它进行:
- 全局搜索;
- 文件索引;
- 快速跳转(Ctrl + P)。
由此可推断: 👉 这是 VSCode Remote - WSL 自动触发的全盘索引。
4、原因分析:误在根目录 / 打开 VSCode
当我打开 WSL 时,执行了:
code /
这看似无害,但实际上 VSCode 会:
- 调用
ripgrep从根目录/开始递归扫描; - 扫描
/mnt/c,/mnt/d(即整个 Windows 文件系统); - 递归进入
/proc,/sys,/usr,/lib等系统目录; - 导致 ripgrep 无限读取上百万个文件。
结果:
- 每个核心都在做 I/O;
vmmemWSL长期满载;- 整机噪音、温度飙升。
5、解决过程
✅ 1️⃣ 终止异常进程
在 WSL 中执行:
sudo pkill -9 rg
CPU 立即恢复正常。
✅ 2️⃣ 修改 VSCode 配置,排除 /mnt/**
创建或编辑项目内的 .vscode/settings.json:
{
"search.exclude": {
"/mnt/**": true,
"**/node_modules": true,
"**/.git": true
},
"files.watcherExclude": {
"/mnt/**": true,
"**/node_modules/**": true,
"**/.git/**": true
},
"search.maxResults": 10000,
"search.followSymlinks": false
}
💡
/mnt/**是关键,避免 VSCode 扫描整个 Windows 文件系统。
✅ 3️⃣ 再次测试
重新打开 VSCode:
code /
- 打开初期(1–2 秒):
rg短暂占用 1200% CPU(初始化索引)
- 之后:
- CPU 降回
<5% vmmemWSL稳定在 1–2%
- CPU 降回
说明配置生效 ✅。
6、进一步优化建议
| 优化项 | 配置 | 说明 |
|---|---|---|
| 限制 ripgrep 线程 | "search.ripgrep.maxThreads": 4 | 降低启动峰值 CPU |
| 禁止符号索引 | "search.quickOpen.includeSymbols": false | 减少启动 I/O |
| 限制 WSL 资源 | .wslconfig 中添加: [wsl2] processors=6 memory=6GB | 避免 runaway 占用 |
| 正确打开路径 | code /home/用户名/项目名 | 永远不要打开 / 或 /mnt |
7、最终状态与验证
| 时间点 | 现象 | 说明 |
|---|---|---|
| 打开 VSCode 0–2 秒 | CPU 1000%+ | 索引初始化 |
| 3 秒后 | CPU 降至 <5% | 搜索停止 |
| 长期运行 | node 0–2%,vmmemWSL <5% | 稳定 |
Windows 任务管理器中:
vmmemWSL.exe 使用率 2%~5%,内存 1.5GB 左右
系统恢复安静、温度正常。
8、经验总结
| 分类 | 错误操作 | 正确做法 |
|---|---|---|
| 打开路径 | 在 / 下打开 VSCode | 打开具体项目目录 |
| 索引范围 | 未排除 /mnt/** | 明确排除 Windows 挂载盘 |
| 占用排查 | 只看 vmmemWSL | 进入 WSL 内部用 top 定位 |
| 快速恢复 | 重启电脑 | sudo pkill -9 rg 即可 |
9、启示与经验
- vmmemWSL 是症状,不是原因。 真正的高负载往往来自 WSL 内部进程。
- VSCode Remote-WSL 极易误扫
/mnt。 这是最常见的性能陷阱。 - 监控工具组合使用:
- Windows:任务管理器定位整体;
- Linux:
top/htop/ps aux精确找出源头。
- 善用配置文件隔离问题:
.vscode/settings.json、.wslconfig都是控制性能的关键。
10、总结
这次排查过程虽然简单,但非常典型:
一个不经意的操作(在根目录打开 VSCode) → 触发了
ripgrep无限扫描 → 造成了“vmmemWSL CPU 高占用”的假象。
最终通过:
top精确定位;pkill rg临时止血;.vscode/settings.json永久屏蔽/mnt; 成功解决。
11、附录:完整 .vscode/settings.json 模板
{
"search.exclude": {
"/mnt/**": true,
"**/node_modules": true,
"**/.git": true
},
"files.watcherExclude": {
"/mnt/**": true,
"**/node_modules/**": true,
"**/.git/**": true
},
"search.maxResults": 10000,
"search.followSymlinks": false,
"search.ripgrep.maxThreads": 4,
"search.quickOpen.includeSymbols": false
}
11.1、 "search.exclude": { "/mnt/**": true, "**/node_modules": true, "**/.git": true }
用途:控制「搜索视图」(Ctrl+Shift+F)和 Quick Open 的文件集合——被排除的目录不会被递归扫描,也不会出现在搜索结果中。
效果:大幅降低 ripgrep (rg) 的 I/O 与 CPU 消耗。
"/mnt/**": true- 含义:从工作区根目录开始,排除
/mnt下所有层级的内容。 - 要点:如果你把工作区根设为
/(即code /),这条规则才能命中真正的系统/mnt。 若工作区根是/home/you/project,那么/mnt/**只会匹配到~/project/mnt/**,不会匹配系统的/mnt。 - 实践建议:你现在会在
/打开,故该规则能精准避免扫描 Windows 盘(/mnt/c、/mnt/d)。
- 含义:从工作区根目录开始,排除
"**/node_modules": true、"**/.git": true- 含义:在任意层级排除
node_modules与.git,两者体量大、文件多,是常见热点。
- 含义:在任意层级排除
📌 注意:
search.exclude只影响搜索集合,不影响「文件监视」与「资源管理器可见性」。后两者看下面的files.watcherExclude。
11.2、 "files.watcherExclude": { "/mnt/**": true, "**/node_modules/**": true, "**/.git/**": true }
用途:告诉 VS Code 的文件系统监听器(watcher)不要订阅这些路径的变更事件。 效果:减少后台文件事件合并、队列、去抖动等 CPU 活动,降低内存占用与卡顿。
"/mnt/**": true- 在工作区根为
/时,避免订阅整个 Windows 盘的文件变更事件(由此避免 “动一下 Windows 文件,WSL 里就忙起来”)。
- 在工作区根为
"**/node_modules/**"、"**/.git/**"- 阻止对依赖仓库与 VCS 元数据的实时监听,降低频繁变更时的开销(例如 Git 操作、包管理器写入)。
⚠️ 误区澄清:
files.watcherExclude不影响搜索范围,也不影响你手动打开文件——仅仅是不再“盯着它们看”。
11.3、"search.maxResults": 10000
用途:限制一次搜索最多返回的匹配条目数(显示到 UI 中)。 效果:防止“关键词过热”导致结果爆表、UI 卡顿。
- 性能层面它是“结果上限”,不是“扫描硬上限”。当匹配很稀疏时,rg 仍可能遍历大量文件后才达到 1 万条结果或遍历结束。
- 配合
search.exclude使用,整体 I/O 就能有效压缩。
11.4、 "search.followSymlinks": false
用途:搜索时不跟随符号链接。 好处:
- 防止因为软链把搜索“带出项目外”或形成环路(常见:软链到
/mnt或到上层目录)。 - 减少扫描体积与系统调用。
取舍:如果你的项目刻意用软链组织源码(例如 monorepo 的某些布局),关闭跟随可能漏搜这些被软链包含的路径。此时可按需改为 true,但务必确保不会指到 /mnt。
11.5、"search.ripgrep.maxThreads": 4
用途:限制 rg 的并发线程数。
好处:降低启动瞬间的 CPU 峰值(你之前看到 1200% 就是 rg 按“每核一线程”并行扫描)。
取舍:
- 线程越少,峰值更低、但搜索更慢。